package com.goldsprite.infinityworld.screens.examples.entity;

import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.*;
import com.badlogic.gdx.scenes.scene2d.*;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.utils.*;
import com.badlogic.gdx.utils.viewport.*;
import java.util.*;

import com.badlogic.gdx.Gdx;
import com.goldsprite.gdxcore.screens.GScreen;
import com.goldsprite.infinityworld.assets.GlobalAssets;
import com.goldsprite.utils.math.Vector2;
import com.goldsprite.gdxcore.logs.LogViewerService;

/**
 * 动画器演示：
 * 展示一个游戏世界窗口，内部使用动画器可绘制实体绘制一个人物动画
 */
public class AnimatorExampleScreen extends GScreen {
	private Stage stage;

	private AnimatorExampleScreen.GameWorld world;

	private Window rootLayout;

	private Window win2;

	@Override
	public void create() {
		// 导入资源
		Skin skin = GlobalAssets.getInstance().defaultSkin;
		String roleTexPath = "roles/Soldier.png";
		Texture roleTex = new Texture(Gdx.files.internal(roleTexPath));

		//设置屏幕视口大小
		getScreenManager().setViewport(new FitViewport(960, 540));
		// 创建舞台
		stage = new Stage(getViewport());
		getImp().addProcessor(stage);

		// 创建画布容器
		Vector2 tableSize = getViewSize().clone().scl(4 / 5f);
		rootLayout = new Window("GameWorld", skin);
		//rootLayout.setSize(100, 100);        // 设置初始大小
		//rootLayout.setPosition(getViewCenter().x, getViewCenter().y, Align.center);
		//rootLayout.setResizable(true);
		//rootLayout.setMovable(true);

		win2 = new Window("w2", skin);
		win2.setSize(300, 300);

		LogViewerService logViewer = new LogViewerService(skin, getViewCenter().x, getViewSize().y, "Default");
		win2.add(logViewer.getRootLayout()).expand().fill();

		String lengthStr = new String(new char[100]).replace("\0", "X");
		LogViewerService.logInfo("" + lengthStr);
		for (int i = 0; i < 20; i++)
			LogViewerService.log("A");


		//设置游戏世界视口宽高
		float worldWidth = 960;
		float worldHeight = 540;
		OrthographicCamera cam = new OrthographicCamera();
		Viewport worldViewport = new FitViewport(worldWidth, worldHeight, cam);
		worldViewport.apply(true);

		// 创建游戏世界
		world = new GameWorld();
		world.setViewport(worldViewport);

		//统一动画速度
		float animPerVel = 1;
		// 创建动画器并导入源材质与设置帧单位大小
		AnimatorEntity role = new AnimatorEntity(roleTex, 100, 100);
		//设置动画
		role.addAnimation("Idle", 0, 6, animPerVel/6);
		role.addAnimation("Walk", 1, 8, animPerVel/8);
		role.setCurAnimation("Walk");
		role.setPosition(0, 0);
		//设置实体大小
		role.setScl(3);

		// 注册实体到游戏世界
		world.addEntity(role);

		// 将游戏世界加入容器
		rootLayout.add(world);

		//设置输入监听器测试触摸位置
		rootLayout.addListener(new InputListener(){
				@Override
				public boolean touchDown(InputEvent ev, float x, float y, int pointer, int btn){
					return true;
				}
				@Override
				public void touchDragged(InputEvent ev, float x, float y, int pointer){
					LogViewerService.log(String.format("[游戏视图] 滑动触摸坐标: %.1f, %.1f", x, y));
				}
			});

		SplitPane splitPane = new SplitPane(rootLayout, win2, false, skin);
		splitPane.setFillParent(true);
		splitPane.setSplitAmount(0.6f);
		stage.addActor(splitPane);
	}

	@Override
	public void render(float delta) {
		super.render(delta);

		rootLayout.setZIndex(0);
		win2.setZIndex(2);

		//限制布局在视口内
		float limitY = Math.min(getViewSize().y-10, rootLayout.getY(Align.top));
		rootLayout.setY(limitY, Align.top);
		stage.act(delta);
		stage.draw();
	}

	public class GameWorld extends Actor {
		private final Array<IRenderable> entities = new Array<>();
		private Viewport viewport;
		private OrthographicCamera cam;

		public void setViewport(Viewport viewport){
			this.viewport = viewport;
			this.cam = (OrthographicCamera)viewport.getCamera();
		}
		public void updateViewport(float width, float height) {
			viewport.update((int) width, (int) height, true);
		}

		public void addEntity(IRenderable entity) {
			entities.add(entity);
			entity.setWorld(this);
		}

		public void removeEntity(IRenderable entity) {
			entities.removeValue(entity, true);
		}

		@Override
		public void draw(Batch batch, float parentAlpha) {
			//Matrix4 oldMatrix = batch.getProjectionMatrix();
			//batch.setProjectionMatrix(cam.combined);
			for (IRenderable entity : entities) {
				entity.render(batch, Gdx.graphics.getDeltaTime());
			}
			//batch.setProjectionMatrix(oldMatrix);
		}
	}

	public interface IRenderable {
		void render(Batch batch, float delta);

		void setWorld(GameWorld world);
	}

	public class Renderable implements IRenderable {
		protected GameWorld world;

		@Override
		public void render(Batch batch, float delta) {}

		@Override
		public void setWorld(GameWorld world) {
			this.world = world;
		}
	}

	public class AnimatorEntity extends Renderable {
		private final Texture animTextures;
		private final TextureRegion[][] regions;
		private final Map<String, Animation> animations = new HashMap<>();
		private Animation curAnimation;
		private float stateTime;
		private Vector2 position = new Vector2();
		private Vector2 texSize = new Vector2();
		private Vector2 size = new Vector2();
		private Vector2 scl = new Vector2(1, 1);

		public AnimatorEntity(Texture animTextures, int frameWidth, int frameHeight) {
			this.animTextures = animTextures;
			//将源材质按素材宽高单位分割
			regions = TextureRegion.split(animTextures, frameWidth, frameHeight);
			texSize.set(frameWidth, frameHeight);
		}

		public void setScl(float scl) { setScl(scl, scl); }
		public void setScl(float sclX, float sclY) {
			scl.set(sclX, sclY);
		}
		public Vector2 getSize() {
			return size.set(texSize.x * scl.x, texSize.y * scl.y);
		}
		public void setCenterPosition(float cx, float cy) {
			Vector2 size = getSize();
			setPosition(cx - size.x / 2, cy - size.y / 2);
		}
		public void setPosition(float x, float y){
			position.set(x, y);
		}
		public Vector2 getPosition(){ return position; }

		//往动画组添加动画：指定动画状态名，要切割的材质行数索引与帧数，以及设置动画播放速率
		public void addAnimation(String name, int row, int frameCount, float frameDuration) {
			//按帧数创建动画帧组
			TextureRegion[] frames = new TextureRegion[frameCount];
			//从源regions目标行填充到动画帧组
			System.arraycopy(regions[row], 0, frames, 0, frameCount);
			//在动画组创建新的动画帧组并设置播放帧率
			animations.put(name, new Animation(frames, frameDuration));
		}

		//设置当前动画
		public void setCurAnimation(String name) {
			curAnimation = animations.get(name);
			stateTime = 0;//切换动画重置播放时间
		}

		//渲染动画
		@Override
		public void render(Batch batch, float delta) {
			if (curAnimation == null) return;
			//获取当前帧
			TextureRegion frame = curAnimation.getFrame(stateTime);
			//在画布绘制
			batch.draw(frame, position.x, position.y, getSize().x, getSize().y);
			//步进动画时间
			stateTime += delta;
		}
	}

	//自定义动画类
	public static class Animation {
		private final TextureRegion[] frames;
		private final float frameDuration;

		public Animation(TextureRegion[] frames, float frameDuration) {
			this.frames = frames;
			this.frameDuration = frameDuration;
		}

		//从播放时间获取当前帧
		public TextureRegion getFrame(float stateTime) {
			int frameIndex = (int) (stateTime / frameDuration) % frames.length;
			return frames[frameIndex];
		}
	}
}

